package com.katesoft.scale4j.common.utils;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/** @author kate2007 */
public class ReflectionUtility
{
    /**
     * Return actual parameter type for generic subclass or interface.
     * <p/>
     * Note:
     * <p/>
     * 1)this method assume that given class is parameterized subclass(interface) and parent class is not {@link Object} so may cause {@link
     * NullPointerException} at runtime.
     * <p/>
     * 2)this method assume that genericSuperClass is ParameterizedType and even does not validate it so may  produce {@link ClassCastException} at
     * runtime.
     * <p/>
     * 3)this method assume that given index is valid so may produce {@link IndexOutOfBoundsException} at runtime.
     *
     * @param clazz target class
     *
     * @param index position of type.
     * @return actual parameterized type.
     */
    public static Class<?> getActualGenericType(final Class<?> clazz,
                                                final int index)
    {
        if (clazz.isInterface()) {
            for (final Type type : clazz.getGenericInterfaces()) {
                if (type instanceof ParameterizedType) { return (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[index]; }
            }
        }
        return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[index];
    }

    /**
     * Build method signature and return human readable simplified signature.
     * <p/>
     * For example method <code>void foo(java.land.String s, com.katesoft.jvmcluster.persistent.User)</code> will have signature like this
     * <code>foo(String, User)</code>.
     *
     * @param m target method.
     *
     * @return simplified signature of the given method.
     */
    public static String buildMethodSignature(final Method m)
    {
        final StringBuilder args = new StringBuilder();
        for (
            @SuppressWarnings("rawtypes")
            final Class i : m.getParameterTypes()) {
            if (args.length() > 0) { args.append(","); }
            args.append(i != null ? i.getSimpleName() : null);
        }
        return m.getName() + "(" + args.toString() + ")";
    }

    private ReflectionUtility() {}
}
